/***************************************************************************//**
* \file cy_capsense_control.c
* \version 3.0
*
* \brief
* This file provides the source code to the Control module functions.
*
********************************************************************************
* \copyright
* Copyright 2018-2021, Cypress Semiconductor Corporation (an Infineon company)
* or an affiliate of Cypress Semiconductor Corporation. All rights reserved.
* You may use this file only in accordance with the license, terms, conditions,
* disclaimers, and limitations in the end user license agreement accompanying
* the software package with which this file was provided.
*******************************************************************************/


#include <stddef.h>
#include "cy_syslib.h"
#include "cy_syspm.h"
#include "cycfg_capsense_defines.h"
#include "cy_capsense_common.h"
#include "cy_capsense_structure.h"
#include "cy_capsense_control.h"
#include "cy_capsense_processing.h"
#include "cy_capsense_filter.h"
#include "cy_capsense_tuner.h"
#include "cy_capsense_sensing.h"
#include "cy_capsense_selftest.h"
#if (CY_CAPSENSE_PLATFORM_BLOCK_FOURTH_GEN)
    #include "cy_capsense_sensing_v2.h"
    #include "cy_csd.h"
#else /* (CY_CAPSENSE_PLATFORM_BLOCK_FIFTH_GEN) */
    #include "cy_capsense_sensing_v3.h"
    #include "cy_msc.h"
#endif

#if (defined(CY_IP_MXCSDV2) || defined(CY_IP_M0S8CSDV2) || defined(CY_IP_M0S8MSCV3))

/*******************************************************************************
* Function Name: Cy_CapSense_Init
****************************************************************************//**
*
* Captures HW blocks (one or more) for CAPSENSE&trade; operations and configures them
* to the default state. Call this function with the application program
* prior to calling any other function of the middleware.
*
* The following tasks are executed:
* 1. Capturing not used HW blocks. If any
*    of HW block is
*    already in use, then the function returns the fail status, and
*    the application program should perform corresponding actions. For example, releasing
*    the HW block captured by another middleware.
* 2. If the HW block has been captured successfully, this function configures it
*    to the default state.
*
* After the middleware is configured using the Cy_CapSense_Init() function,
* the application program configures and enables the HW block interrupt(s),
* and then call of the Cy_CapSense_Enable() function to complete the
* middleware initialization process.
* See the function usage example below for more details.
*
* When the middleware operation is stopped by the Cy_CapSense_DeInit()
* function, subsequent call of the Cy_CapSense_Init() function repeats
* initialization process and it is not needed to call the Cy_CapSense_Enable()
* function second time. However, to implement time-multiplexed mode
* (sharing the HW block(s) between multiple middleware)
* the Cy_CapSense_Save() and Cy_CapSense_Restore() functions should be used
* instead of the Cy_CapSense_DeInit() and Cy_CapSense_Init() functions for
* further compatibility.
*
* \param context
* The pointer to the CAPSENSE&trade; context structure \ref cy_stc_capsense_context_t
* generated by the CAPSENSE&trade; Configurator tool. The structure contains both, CAPSENSE&trade;
* configuration and internal data and it is used during whole CAPSENSE&trade; operation.
*
* \return
* Returns the status of the initialization process. If CY_CAPSENSE_STATUS_SUCCESS is not
* received, some of the initialization fails, the middleware may not operate
* as expected, and repeating of initialization is required.
*
* \funcusage
*
* \snippet capsense/snippet/main.c snippet_Cy_CapSense_Initialization
* The 'cy_capsense_context' variable that is used as the parameter of the
* Cy_CapSense_Init() and Cy_CapSense_Enable() functions is declared in the
* cycfg_capsense.h file.
*
* The CapSense_ISR_cfg variable should be declared by the application
* program according to the examples below:<br>
* For PSoC&trade; 4 CPU or for PSoC&trade; 6 CM0+ core:
* \snippet capsense/snippet/main.c snippet_m0p_capsense_interrupt_source_declaration
*
* For CM4 core:
* \snippet capsense/snippet/main.c snippet_m4_capsense_interrupt_source_declaration
*
* The CAPSENSE&trade; interrupt handler should be declared by the application program
* according to the example below:
* \snippet capsense/snippet/main.c snippet_Cy_CapSense_IntHandler
*
* The CapSense_HW is the pointer to the base register address of
* the CAPSENSE&trade; HW block. A macro for the pointer is in the cycfg_peripherals.h
* file defined as \<Personality_Name\>_HW. If no name is specified,
* the following default names are used:
* * csd_\<Block_Number\>_csd_\<Block_Number\>_HW - for forth-generation CAPSENSE&trade; HW.
* * msc_\<Block_Number\>_msc_\<Block_Number\>_HW - for fifth-generation CAPSENSE&trade; HW.
*
*******************************************************************************/
cy_capsense_status_t Cy_CapSense_Init(cy_stc_capsense_context_t * context)
{
    cy_capsense_status_t result = CY_CAPSENSE_STATUS_BAD_PARAM;
    cy_stc_capsense_internal_context_t * ptrInternalCxt;

    #if (CY_CAPSENSE_PLATFORM_BLOCK_FIFTH_GEN)
        #if ((CY_CAPSENSE_ENABLE == CY_CAPSENSE_SMARTSENSE_FULL_EN) || \
             (CY_CAPSENSE_ENABLE == CY_CAPSENSE_SMARTSENSE_HW_EN))
            uint32_t wdIndex;
            cy_stc_capsense_widget_context_t * ptrWdCxt;
            const cy_stc_capsense_widget_config_t * ptrWdCfg;
        #endif
        const cy_stc_capsense_common_config_t * ptrCommonCfg;
    #endif

    if (NULL != context)
    {
        ptrInternalCxt = context->ptrInternalContext;
        ptrInternalCxt->intrCsdInactSnsConn = CY_CAPSENSE_SNS_CONNECTION_UNDEFINED;
        ptrInternalCxt->intrCsxInactSnsConn = CY_CAPSENSE_SNS_CONNECTION_UNDEFINED;
        ptrInternalCxt->ptrSSCallback = NULL;
        ptrInternalCxt->ptrEOSCallback = NULL;
        ptrInternalCxt->ptrTunerReceiveCallback = NULL;
        ptrInternalCxt->ptrTunerSendCallback = NULL;

        #if (CY_CAPSENSE_PLATFORM_BLOCK_FIFTH_GEN)
            #if ((CY_CAPSENSE_ENABLE == CY_CAPSENSE_SMARTSENSE_FULL_EN) || \
                 (CY_CAPSENSE_ENABLE == CY_CAPSENSE_SMARTSENSE_HW_EN))
                ptrWdCfg = context->ptrWdConfig;
                for (wdIndex = 0u; wdIndex < context->ptrCommonConfig->numWd; wdIndex++)
                {
                    ptrWdCxt = ptrWdCfg->ptrWdContext;
                    if(CY_CAPSENSE_CSD_GROUP == ptrWdCfg->senseMethod)
                    {
                        ptrWdCxt->snsClk = CY_CAPSENSE_SMARTSENSE_PRELIMINARY_SCAN_SNS_CLK;
                        ptrWdCxt->rowSnsClk = CY_CAPSENSE_SMARTSENSE_PRELIMINARY_SCAN_SNS_CLK;
                    }

                    ptrWdCfg++;
                }
            #endif

            ptrCommonCfg = context->ptrCommonConfig;
            result = Cy_CapSense_SwitchHwConfiguration(CY_CAPSENSE_HW_CONFIG_UNDEFINED, context);

            ptrInternalCxt->ptrEODsInitCallback = NULL;

            ptrInternalCxt->numEpiCycles = ptrCommonCfg->numEpiCycles;
            ptrInternalCxt->numCoarseInitChargeCycles = ptrCommonCfg->numCoarseInitChargeCycles;
            ptrInternalCxt->numCoarseInitSettleCycles = ptrCommonCfg->numCoarseInitSettleCycles;
            ptrInternalCxt->numFineInitWaitCycles = context->ptrCommonContext->numFineInitWaitCycles;
            ptrInternalCxt->numProOffsetCycles = ptrCommonCfg->numProOffsetCycles;
            ptrInternalCxt->proOffsetCdacComp = ptrCommonCfg->proOffsetCdacComp;

            /* Set auto-calibration internal parameters */
            ptrInternalCxt->intrCsdRawTarget = ptrCommonCfg->csdRawTarget;
            ptrInternalCxt->intrCsxRawTarget = ptrCommonCfg->csxRawTarget;

            #if (CY_CAPSENSE_SCAN_MODE_DMA_DRIVEN == CY_CAPSENSE_SCAN_MODE)
                /* Set undefined value to initiate DMA configuration in Cy_CapSense_ScanSlots() function */
                context->ptrInternalContext->currentSlotIndex = CY_CAPSENSE_SLOT_COUNT_MAX_VALUE;
            #endif

            if (CY_CAPSENSE_STATUS_SUCCESS == result)
            {
                result = Cy_CapSense_Restore(context);
            }
        #else
            result = Cy_CapSense_Restore(context);
        #endif

        /* The time interval is required for settling analog part of the HW block. */
        Cy_SysLib_DelayUs(CY_CAPSENSE_ANALOG_SETTLING_TIME_US);
    }

    return result;
}


/*******************************************************************************
* Function Name: Cy_CapSense_Enable
****************************************************************************//**
*
* Initializes the CAPSENSE&trade; firmware modules.
*
* Call the Cy_CapSense_Init() function and configure CAPSENSE&trade; HW block interrupts
* prior to calling this function.
* See the function usage example below for details on usage.
*
* The following are executed as part of the function:
* 1. Check CAPSENSE&trade; configuration integrity.
* 2. Pre-calculate of internal register values to speed up operation.
* 3. Configure the CAPSENSE&trade; HW block to perform capacitive sensing operation.
* 4. If the smart sensing algorithm is selected for the CSD Tuning mode in the
*    Basic tab, the auto-tuning functionality is executed to set the optimal
*    values for the CAPSENSE&trade; HW block parameters of the widgets/sensors.
* 5. Calibrate the sensors and find the optimal values for DACs of each widget/sensor,
*    if the auto-calibration is enabled in the CSD Setting or CSX Setting tabs.
* 6. Perform scanning for all the sensors and initialize the baseline history.
* 7. If the firmware filters are enabled in the Advanced General tab, the
*    filter histories are also initialized.
*
* Any subsequent call of this function repeats initialization process.
* Therefore, it is possible to change the middleware configuration
* from the application program by writing registers to the data structure
* and calling this function again.
*
* The repeated call of this function is also done inside the
* Cy_CapSense_RunTuner() function when a restart command is received.
*
* \param context
* The pointer to the CAPSENSE&trade; context structure \ref cy_stc_capsense_context_t.
*
* \return
* Returns the status of the initialization process. If CY_CAPSENSE_STATUS_SUCCESS is not
* received, some of the initialization fails.
*
* \funcusage
*
* \snippet capsense/snippet/main.c snippet_Cy_CapSense_Initialization
* The 'cy_capsense_context' variable that is used as the parameter of the
* Cy_CapSense_Init() and Cy_CapSense_Enable() functions is declared in the
* cycfg_capsense.h file.
*
* The CapSense_ISR_cfg variable should be declared by the application
* program according to the examples below:<br>
* For CM0+ core:
* \snippet capsense/snippet/main.c snippet_m0p_capsense_interrupt_source_declaration
*
* For CM4 core:
* \snippet capsense/snippet/main.c snippet_m4_capsense_interrupt_source_declaration
*
* The CAPSENSE&trade; interrupt handler should be declared by the application program
* according to the example below:
* \snippet capsense/snippet/main.c snippet_Cy_CapSense_IntHandler
*
* The CapSense_HW is the pointer to the base register address of
* the CAPSENSE&trade; HW block. A macro for the pointer is in the cycfg_peripherals.h
* file defined as \<Personality_Name\>_HW. If no name is specified,
* the following default names are used:
* * csd_\<Block_Number\>_csd_\<Block_Number\>_HW - for forth-generation CAPSENSE&trade; HW.
* * msc_\<Block_Number\>_msc_\<Block_Number\>_HW - for fifth-generation CAPSENSE&trade; HW.
*
*******************************************************************************/
cy_capsense_status_t Cy_CapSense_Enable(cy_stc_capsense_context_t * context)
{
    cy_capsense_status_t result;
    uint32_t cpuFreqMHz;
    uint32_t watchdogCounter;
    #if (CY_CAPSENSE_PLATFORM_BLOCK_FIFTH_GEN)
        context->ptrCommonContext->status |= CY_CAPSENSE_MW_STATE_INITIALIZATION_MASK;
        uint32_t widgetId;
    #endif /* (CY_CAPSENSE_PLATFORM_BLOCK_FIFTH_GEN) */

    /* Approximate duration of Wait For Init loop */
    const uint32_t isBusyLoopDuration = 5uL;

    /* Wait For Init watchdog timeout in microseconds */
    const uint32_t isBusyWatchdogTimeUs = 1000000uL;

    /* Initialize CAPSENSE&trade; modules */
    result = Cy_CapSense_Initialize(context);

    if(CY_CAPSENSE_STATUS_SUCCESS == result)
    {
        #if (CY_CAPSENSE_PLATFORM_BLOCK_FOURTH_GEN)
            #if ((CY_CAPSENSE_ENABLE == CY_CAPSENSE_SMARTSENSE_FULL_EN) || \
                 (CY_CAPSENSE_ENABLE == CY_CAPSENSE_SMARTSENSE_HW_EN))
                result |= Cy_CapSense_SsAutoTune(context);
            #elif (CY_CAPSENSE_ENABLE == CY_CAPSENSE_CSD_CALIBRATION_EN)
                    result |= Cy_CapSense_CalibrateAllCsdWidgets(context);
            #endif

            #if (CY_CAPSENSE_ENABLE == CY_CAPSENSE_CSX_CALIBRATION_EN)
                result |= Cy_CapSense_CalibrateAllCsxWidgets(context);
            #endif
        #else /* (CY_CAPSENSE_PLATFORM_BLOCK_FIFTH_GEN) */
            #if ((CY_CAPSENSE_ENABLE == CY_CAPSENSE_SMARTSENSE_FULL_EN) || \
                 (CY_CAPSENSE_ENABLE == CY_CAPSENSE_SMARTSENSE_HW_EN))
                result |= Cy_CapSense_SsAutoTune(context);
            #endif
            #if ((CY_CAPSENSE_ENABLE == CY_CAPSENSE_CSD_CALIBRATION_EN) || \
                (CY_CAPSENSE_ENABLE == CY_CAPSENSE_CSX_CALIBRATION_EN))
                {
                    result |= Cy_CapSense_CalibrateAllSlots(context);
                }
            #endif
        #endif

        result |= Cy_CapSense_ScanAllWidgets(context);

        /* Init Watchdog Counter to prevent a hang */
        cpuFreqMHz = context->ptrCommonConfig->cpuClkHz / CY_CAPSENSE_CONVERSION_MEGA;
        watchdogCounter = Cy_CapSense_WatchdogCyclesNum(isBusyWatchdogTimeUs, cpuFreqMHz, isBusyLoopDuration);

        while (CY_CAPSENSE_NOT_BUSY != Cy_CapSense_IsBusy(context))
        {
            if(0uL == watchdogCounter)
            {
                break;
            }

            watchdogCounter--;
        }

        #if (CY_CAPSENSE_PLATFORM_BLOCK_FIFTH_GEN)
            for (widgetId = 0u; widgetId < context->ptrCommonConfig->numWd; widgetId++)
            {
                Cy_CapSense_PreProcessWidget(widgetId, context);
                #if (CY_CAPSENSE_DISABLE != CY_CAPSENSE_MULTI_PHASE_ENABLED)
                    if (CY_CAPSENSE_MPTX_MIN_ORDER <= context->ptrWdConfig[widgetId].mptxOrder)
                    {
                        result |= Cy_CapSense_ProcessWidgetMptxDeconvolution(widgetId, context);
                    }
                #endif
            }
        #endif
    }

    #if (CY_CAPSENSE_DISABLE != CY_CAPSENSE_RAWCOUNT_FILTER_EN)
        Cy_CapSense_InitializeAllFilters(context);
    #endif
    Cy_CapSense_InitializeAllBaselines(context);

    #if (CY_CAPSENSE_PLATFORM_BLOCK_FIFTH_GEN)
        context->ptrCommonContext->status &= ~(uint32_t)CY_CAPSENSE_MW_STATE_INITIALIZATION_MASK;
    #endif /* (CY_CAPSENSE_PLATFORM_BLOCK_FIFTH_GEN) */

    return result;
}


/*******************************************************************************
* Function Name: Cy_CapSense_Initialize
****************************************************************************//**
*
* Initializes all sub-modules of the CAPSENSE&trade; middleware.
*
* The initialization includes:
* - Data Structure - set the default middleware parameters based
*   on configuration.
* - Data Processing - resets the status all widgets.
* - Tuner - resets the tuner communication state.
* - Sensing - prepares the CAPSENSE&trade; HW blocks for operation.
*
* \param context
* The pointer to the CAPSENSE&trade; context structure \ref cy_stc_capsense_context_t.
*
* \return
* Return CY_CAPSENSE_STATUS_SUCCESS if the initialization was successful.
*
*******************************************************************************/
cy_capsense_status_t Cy_CapSense_Initialize(cy_stc_capsense_context_t * context)
{
    cy_capsense_status_t result;

    result = Cy_CapSense_CheckConfigIntegrity(context);
    if (CY_CAPSENSE_STATUS_SUCCESS == result)
    {
        Cy_CapSense_InitializeAllStatuses(context);

        result |= Cy_CapSense_SsInitialize(context);

        /* The Tuner and the BIST are initialized only once */
        if (CY_CAPSENSE_INIT_NEEDED == context->ptrCommonContext->initDone)
        {
            Cy_CapSense_TuInitialize(context);

            #if (CY_CAPSENSE_ENABLE == CY_CAPSENSE_BIST_EN)
                Cy_CapSense_BistDsInitialize(context);
            #endif /* (CY_CAPSENSE_ENABLE == CY_CAPSENSE_BIST_EN) */

            context->ptrCommonContext->initDone = CY_CAPSENSE_INIT_DONE;
        }
    }

    return (result);
}


/*******************************************************************************
* Function Name: Cy_CapSense_DeInit
****************************************************************************//**
*
* Stops the middleware operation and releases the CAPSENSE&trade; captured HW blocks.
*
* No sensor scanning can be executed when the middleware is stopped.
* This function should be called only when no scanning is in progress.
* I.e. Cy_CapSense_IsBusy() returns a non-busy status.
*
* After the middleware stops, the CAPSENSE&trade; HW block(s) may be reconfigured with the
* application program or other middleware for any other usage.
*
* When the middleware operation is stopped by the Cy_CapSense_DeInit()
* function, subsequent call of the Cy_CapSense_Init() function repeats
* initialization process and it is not needed to call the Cy_CapSense_Enable()
* function second time. However, to implement time-multiplexed mode
* (sharing the CAPSENSE&trade; HW block(s) between multiple middleware)
* the Cy_CapSense_Save() and Cy_CapSense_Restore() functions should be used
* instead of the Cy_CapSense_DeInit() and Cy_CapSense_Init() functions for
* further compatibility.
*
* \param context
* The pointer to the CAPSENSE&trade; context structure \ref cy_stc_capsense_context_t.
*
* \return
* Returns the status of the stop process. If CY_CAPSENSE_STATUS_SUCCESS is not received,
* the stop process fails and retries may be required.
*
*******************************************************************************/
cy_capsense_status_t Cy_CapSense_DeInit(cy_stc_capsense_context_t * context)
{
    cy_capsense_status_t result;

    result = Cy_CapSense_Save(context);
    if (CY_CAPSENSE_STATUS_SUCCESS != result)
    {
        result = CY_CAPSENSE_STATUS_BAD_DATA;
    }
    else
    {
        context->ptrCommonContext->initDone = CY_CAPSENSE_INIT_NEEDED;
    }

    return (result);
}


/*******************************************************************************
* Function Name: Cy_CapSense_ProcessAllWidgets
****************************************************************************//**
*
* Performs full data processing of all enabled widgets.
*
* This function performs all data processes for all enabled widgets and
* sensors in the middleware to produce meaningful status output from widgets
* and sensors. The following tasks are executed as part of processing all the
* widgets:
* 1. Apply raw count filters to the raw counts, if they are enabled.
* 2. Update the thresholds if the smart sensing algorithm Full Auto-Tuning
*    is enabled.
* 3. Update the baselines and difference counts for all the sensors.
* 4. Update the sensor and widget output status. Updates on/off status for
*    buttons and proximity widgets, centroid/position for
*    the sliders and the X/Y position for the touchpads.
*
* This function is called by the application program only after all the enabled
* widgets (and sensors) in the middleware are scanned. Calling this function
* multiple times without sensor scanning causes unexpected behavior.
*
* The disabled widgets are not processed by this function.
*
* \param context
* The pointer to the CAPSENSE&trade; context structure \ref cy_stc_capsense_context_t.
*
* \return
* Returns the status of the processing operation. If CY_CAPSENSE_STATUS_SUCCESS is not received,
* the processing fails and retries may be required.
*
*******************************************************************************/
cy_capsense_status_t Cy_CapSense_ProcessAllWidgets(cy_stc_capsense_context_t * context)
{
    uint32_t wdIndex;
    cy_capsense_status_t result = CY_CAPSENSE_STATUS_SUCCESS;

    for (wdIndex = context->ptrCommonConfig->numWd; wdIndex-- > 0u;)
    {
        #if ((CY_CAPSENSE_PLATFORM_BLOCK_FIFTH_GEN) && (CY_CAPSENSE_DISABLE != CY_CAPSENSE_MULTI_FREQUENCY_WIDGET_EN))
            if (0u == ((&context->ptrWdConfig[wdIndex])->mfsConfig & CY_CAPSENSE_MFS_WIDGET_FREQ_ALL_CH_MASK))
            {
                /* Processes all widgets with disabled MFS and all widgets with original (main) frequency */
                result |= Cy_CapSense_ProcessWidget(wdIndex, context);
            }
        #else
            result |= Cy_CapSense_ProcessWidget(wdIndex, context);
        #endif
    }
    return result;
}


/*******************************************************************************
* Function Name: Cy_CapSense_ProcessWidget
****************************************************************************//**
*
* Performs full data processing of the specified widget if it is enabled.
*
* This function performs exactly the same tasks as
* Cy_CapSense_ProcessAllWidgets(), but only for a specified widget. This
* function can be used along with the Cy_CapSense_SetupWidget() and
* Cy_CapSense_Scan() functions (4th Generation) to scan and process data for a specific
* widget or with the Cy_CapSense_ScanSlots() function (5th Generation).
* This function is called only after all the sensors in the
* widgets are scanned. A disabled widget is not processed by this function.
*
* A pipeline scan method (i.e. during scanning of a current widget (N),
* perform processing of the previously scanned widget (N-1)) can be
* implemented using this function and it may reduce the total execution time,
* increase the refresh rate, and decrease the average power consumption.
* See the function usage example below for details on usage.
*
* For the Fifth generation CapSense if the specified widget has the enabled
* multi-frequency scan feature then the function does the following:
* - If the specified widget ID refers to main (base) frequency then the function
* processes raw count processing of all three widgets (main and two sub-widgets)
* and then status processing of the main widget only.
* - If the specified widget ID refers to sub-widgets (1st or 2nd frequency channels)
* then the function returns CY_CAPSENSE_STATUS_BAD_PARAM. To perform customized
* processing use the Cy_CapSense_ProcessWidgetExt() function.
*
* \param widgetId
* Specifies the ID number of the widget. A macro for the widget ID can be found
* in the cycfg_capsense.h file defined as CY_CAPSENSE_<WIDGET_NAME>_WDGT_ID.
*
* \param context
* The pointer to the CAPSENSE&trade; context structure \ref cy_stc_capsense_context_t.
*
* \return
* Returns the status of the widget processing:
* - CY_CAPSENSE_STATUS_SUCCESS       - The operation is successfully completed
* - CY_CAPSENSE_STATUS_BAD_PARAM     - The input parameter is invalid
* - CY_CAPSENSE_STATUS_INVALID_STATE - The specified widget is disabled
* - CY_CAPSENSE_STATUS_BAD_DATA      - The processing is failed
*
* \funcusage
*
* An example of pipeline implementation:
* \snippet capsense/snippet/main.c snippet_Cy_CapSense_ProcessWidget
*
*******************************************************************************/
cy_capsense_status_t Cy_CapSense_ProcessWidget(
                uint32_t widgetId,
                cy_stc_capsense_context_t * context)
{
    cy_capsense_status_t result = CY_CAPSENSE_STATUS_SUCCESS;
    const cy_stc_capsense_widget_config_t * ptrWdCfg;

    /* Check parameter validity */
    if (widgetId >= context->ptrCommonConfig->numWd)
    {
        result = CY_CAPSENSE_STATUS_BAD_PARAM;
    }

    if (CY_CAPSENSE_STATUS_SUCCESS == result)
    {
        ptrWdCfg = &context->ptrWdConfig[widgetId];
        /* Check widget enable status */
        if (0u != (ptrWdCfg->ptrWdContext->status & CY_CAPSENSE_WD_DISABLE_MASK))
        {
            result = CY_CAPSENSE_STATUS_INVALID_STATE;
        }
        #if ((CY_CAPSENSE_PLATFORM_BLOCK_FIFTH_GEN) && (CY_CAPSENSE_DISABLE != CY_CAPSENSE_MULTI_FREQUENCY_WIDGET_EN))
            /* Check for sub-widget */
            if (0u != (ptrWdCfg->mfsConfig & CY_CAPSENSE_MFS_WIDGET_FREQ_ALL_CH_MASK))
            {
                result |= CY_CAPSENSE_STATUS_BAD_PARAM;
            }
        #endif
    }

    #if (CY_CAPSENSE_PLATFORM_BLOCK_FIFTH_GEN)
        if (CY_CAPSENSE_STATUS_SUCCESS == result)
        {
            #if (CY_CAPSENSE_DISABLE != CY_CAPSENSE_MULTI_FREQUENCY_WIDGET_EN)
                if (0u != (ptrWdCfg->mfsConfig & CY_CAPSENSE_MFS_EN_MASK))
                {
                    Cy_CapSense_PreProcessWidget(widgetId + CY_CAPSENSE_MFS_CH2_INDEX, context);
                    Cy_CapSense_PreProcessWidget(widgetId + CY_CAPSENSE_MFS_CH1_INDEX, context);
                }
            #endif
            Cy_CapSense_PreProcessWidget(widgetId, context);
        }
    #endif

    if (CY_CAPSENSE_STATUS_SUCCESS == result)
    {
        switch(ptrWdCfg->senseMethod)
        {
            #if (CY_CAPSENSE_ENABLE == CY_CAPSENSE_CSD_EN)
                case CY_CAPSENSE_CSD_GROUP:
                    #if (CY_CAPSENSE_DISABLE != CY_CAPSENSE_MULTI_FREQUENCY_WIDGET_EN)
                        if (0u != (ptrWdCfg->mfsConfig & CY_CAPSENSE_MFS_EN_MASK))
                        {
                            /* Processes all sub-widgets of MFS widgets with derivative frequency */
                            result |= Cy_CapSense_DpProcessCsdWidgetRawCounts(widgetId + CY_CAPSENSE_MFS_CH2_INDEX, context);
                            result |= Cy_CapSense_DpProcessCsdWidgetRawCounts(widgetId + CY_CAPSENSE_MFS_CH1_INDEX, context);
                        }
                    #endif
                    result |= Cy_CapSense_DpProcessCsdWidgetRawCounts(widgetId, context);
                    Cy_CapSense_DpProcessCsdWidgetStatus(ptrWdCfg, context);
                    break;
            #endif /* (CY_CAPSENSE_ENABLE == CY_CAPSENSE_CSD_EN) */

            #if (CY_CAPSENSE_ENABLE == CY_CAPSENSE_CSX_EN)
                case CY_CAPSENSE_CSX_GROUP:
                    #if (CY_CAPSENSE_DISABLE != CY_CAPSENSE_MULTI_FREQUENCY_WIDGET_EN)
                        if (0u != (ptrWdCfg->mfsConfig & CY_CAPSENSE_MFS_EN_MASK))
                        {
                            /* Processes all sub-widgets of MFS widgets with derivative frequency */
                            #if ((CY_CAPSENSE_PLATFORM_BLOCK_FIFTH_GEN) && (CY_CAPSENSE_DISABLE != CY_CAPSENSE_MULTI_PHASE_ENABLED))
                                if (CY_CAPSENSE_MPTX_MIN_ORDER <= ptrWdCfg->mptxOrder)
                                {
                                    result |= Cy_CapSense_ProcessWidgetMptxDeconvolution(widgetId + CY_CAPSENSE_MFS_CH2_INDEX, context);
                                    result |= Cy_CapSense_ProcessWidgetMptxDeconvolution(widgetId + CY_CAPSENSE_MFS_CH1_INDEX, context);
                                }
                            #endif
                            result |= Cy_CapSense_DpProcessCsxWidgetRawCounts(widgetId + CY_CAPSENSE_MFS_CH2_INDEX, context);
                            result |= Cy_CapSense_DpProcessCsxWidgetRawCounts(widgetId + CY_CAPSENSE_MFS_CH1_INDEX, context);
                        }
                    #endif
                    #if ((CY_CAPSENSE_PLATFORM_BLOCK_FIFTH_GEN) && (CY_CAPSENSE_DISABLE != CY_CAPSENSE_MULTI_PHASE_ENABLED))
                        if (CY_CAPSENSE_MPTX_MIN_ORDER <= ptrWdCfg->mptxOrder)
                        {
                            result |= Cy_CapSense_ProcessWidgetMptxDeconvolution(widgetId, context);
                        }
                    #endif
                    result |= Cy_CapSense_DpProcessCsxWidgetRawCounts(widgetId, context);
                    Cy_CapSense_DpProcessCsxWidgetStatus(ptrWdCfg);
                    break;
            #endif /* (CY_CAPSENSE_ENABLE == CY_CAPSENSE_CSX_EN) */

            default:
                result |= CY_CAPSENSE_STATUS_BAD_PARAM;
                break;
        }
    }

    return result;
}


/*******************************************************************************
* Function Name: Cy_CapSense_ProcessWidgetExt
****************************************************************************//**
*
* Performs customized data processing on the selected widget.
*
* This function performs customized data processing specified by the mode
* parameter on a widget. This function can be used with any of the
* available scan functions. This function should be called only after all
* the sensors in the specified widget are scanned. Calling this function
* multiple times with the same mode without new sensor scan causes
* unexpected behavior. This function ignores the value of the
* wdgtEnable register.
*
* The CY_CAPSENSE_PROCESS_CALC_NOISE and CY_CAPSENSE_PROCESS_THRESHOLDS masks
* for mode parameter are supported only when smart sensing algorithm is enabled
* for CSD widgets.
*
* The execution order of processing tasks starts from LSB to MSB of the
* mode parameter. To implement a different order of execution, call this
* function multiple times with the required mode parameter.
*
* For more details, refer to function usage example below.
*
* \note
* For the the fifth-generation CAPSENSE&trade; an extra processing should be
* performed prior a call of this function:
* * A raw count pre-processing calling either the Cy_CapSense_PreProcessWidget()
*   or Cy_CapSense_PreProcessSensor() functions.
* * A deconvolution for widgets with multi-phase Tx calling the
*   Cy_CapSense_ProcessWidgetMptxDeconvolution() function.
* In this case a full processing flow consists of the following:
* * Cy_CapSense_PreProcessWidget()
* * Cy_CapSense_ProcessWidgetMptxDeconvolution()
* * Cy_CapSense_ProcessWidgetExt()
*
* \param widgetId
* Specifies the ID number of the widget. A macro for the widget ID can be found
* in the cycfg_capsense.h file defined as CY_CAPSENSE_<WIDGET_NAME>_WDGT_ID.
*
* \param mode
* Specifies the type of widget processing to be executed for the
* specified widget:
* 1. Bits [31..7] - Reserved.
* 2. Bits [6..0]  - CY_CAPSENSE_PROCESS_ALL - Execute all of the below tasks.
* 3. Bit [6]      - CY_CAPSENSE_PROCESS_MFS_FILTER - Run the firmware filters
*                   for MFS on sensor rawcounts
*                   (applicable only for fifth-generation CAPSENSE&trade;).
* 4. Bit [5]      - CY_CAPSENSE_PROCESS_STATUS - Update the status
*                   (on/off, centroid position).
* 5. Bit [4]      - CY_CAPSENSE_PROCESS_THRESHOLDS - Update the thresholds
*                   (only in CSD auto-tuning mode).
* 6. Bit [3]      - CY_CAPSENSE_PROCESS_CALC_NOISE - Calculate the noise
*                   (only in CSD auto-tuning mode).
* 7. Bit [2]      - CY_CAPSENSE_PROCESS_DIFFCOUNTS - Update the difference
*                   counts of each sensor.
* 8. Bit [1]      - CY_CAPSENSE_PROCESS_BASELINE - Update the baselines
*                   for all sensor.
* 9. Bit [0]      - CY_CAPSENSE_PROCESS_FILTER - Run the firmware filters
*                   on sensor rawcounts.
*
* \param context
* The pointer to the CAPSENSE&trade; context structure \ref cy_stc_capsense_context_t.
*
* \return
* Returns the status of the widget processing operation:
* - CY_CAPSENSE_STATUS_SUCCESS      - The processing is successfully performed.
* - CY_CAPSENSE_STATUS_BAD_PARAM    - The input parameter is invalid.
* - CY_CAPSENSE_STATUS_BAD_DATA     - The processing failed.
*
* \funcusage
*
* An example of customized data processing, changed processing order:
* \snippet capsense/snippet/main.c snippet_Cy_CapSense_ProcessWidgetExt
*
*******************************************************************************/
cy_capsense_status_t Cy_CapSense_ProcessWidgetExt(
                uint32_t widgetId,
                uint32_t mode,
                cy_stc_capsense_context_t * context)
{
    uint32_t snsIndex;
    cy_capsense_status_t capStatus = CY_CAPSENSE_STATUS_BAD_PARAM;
    uint32_t snsHistorySize;
    uint32_t freqChIndex;
    uint16_t * ptrHistorySns;
    uint16_t * ptrBslnInvSns;
    uint8_t * ptrHistoryLowSns = NULL;
    cy_stc_capsense_sensor_context_t * ptrSnsCxtSns;
    const cy_stc_capsense_widget_config_t * ptrWdCfg;

    /* Check parameter validity */
    if (widgetId < context->ptrCommonConfig->numWd)
    {
        ptrWdCfg = &context->ptrWdConfig[widgetId];
        snsHistorySize = (uint32_t)ptrWdCfg->rawFilterConfig & CY_CAPSENSE_RC_FILTER_SNS_HISTORY_SIZE_MASK;

        /* Run the desired processing for the all CSD widget sensors */
        for(freqChIndex = 0u; freqChIndex < CY_CAPSENSE_CONFIGURED_FREQ_NUM; freqChIndex++)
        {
            ptrSnsCxtSns = &ptrWdCfg->ptrSnsContext[freqChIndex * context->ptrCommonConfig->numSns];
            ptrBslnInvSns = &ptrWdCfg->ptrBslnInv[freqChIndex * context->ptrCommonConfig->numSns];
            ptrHistorySns = &ptrWdCfg->ptrRawFilterHistory[freqChIndex * (CY_CAPSENSE_RAW_HISTORY_SIZE / CY_CAPSENSE_CONFIGURED_FREQ_NUM)];
            if(CY_CAPSENSE_IIR_FILTER_PERFORMANCE == (ptrWdCfg->rawFilterConfig & CY_CAPSENSE_RC_FILTER_IIR_MODE_MASK))
            {
                ptrHistoryLowSns = &ptrWdCfg->ptrRawFilterHistoryLow[freqChIndex *
                        (CY_CAPSENSE_IIR_HISTORY_LOW_SIZE / CY_CAPSENSE_CONFIGURED_FREQ_NUM)];
            }

            for (snsIndex = 0u; snsIndex < ptrWdCfg->numSns; snsIndex++)
            {
                #if (CY_CAPSENSE_ENABLE == CY_CAPSENSE_CSX_EN)
                    if (CY_CAPSENSE_CSX_GROUP == ptrWdCfg->senseMethod)
                    {
                            capStatus = Cy_CapSense_DpProcessCsxSensorRawCountsExt(ptrWdCfg, ptrSnsCxtSns,
                                    ptrHistorySns, ptrHistoryLowSns, mode, ptrBslnInvSns, context);
                    }
                #endif /* (CY_CAPSENSE_ENABLE == CY_CAPSENSE_CSX_EN) */

                #if (CY_CAPSENSE_ENABLE == CY_CAPSENSE_CSD_EN)
                    if (CY_CAPSENSE_CSD_GROUP == ptrWdCfg->senseMethod)
                    {
                        capStatus = Cy_CapSense_DpProcessCsdSensorRawCountsExt(ptrWdCfg, ptrSnsCxtSns,
                                ptrHistorySns, ptrHistoryLowSns, mode, ptrBslnInvSns, context);
                    }
                #endif /* (CY_CAPSENSE_ENABLE == CY_CAPSENSE_CSD_EN) */

                /* Placeholder for further methods */

                ptrSnsCxtSns++;
                ptrBslnInvSns++;
                ptrHistorySns += snsHistorySize;
                if(NULL != ptrHistoryLowSns)
                {
                    ptrHistoryLowSns++;
                }
            }
        }

        #if ((CY_CAPSENSE_DISABLE != CY_CAPSENSE_MULTI_FREQUENCY_SCAN_EN) && \
            (CY_CAPSENSE_PLATFORM_BLOCK_FOURTH_GEN))
            ptrSnsCxtSns = ptrWdCfg->ptrSnsContext;
            for (snsIndex = ptrWdCfg->numSns; snsIndex-- > 0u;)
            {
                Cy_CapSense_RunMfsFiltering(ptrSnsCxtSns, context);
                ptrSnsCxtSns++;
            }
        #endif

        #if ((CY_CAPSENSE_DISABLE != CY_CAPSENSE_MULTI_FREQUENCY_WIDGET_EN) && \
             (CY_CAPSENSE_PLATFORM_BLOCK_FIFTH_GEN))
            if (0u != (mode & CY_CAPSENSE_PROCESS_MFS_FILTER))
            {
                (void) Cy_CapSense_RunMfsMedian(widgetId, context);
            }
        #endif

        if (0u != (mode & CY_CAPSENSE_PROCESS_STATUS))
        {
            #if (CY_CAPSENSE_ENABLE == CY_CAPSENSE_CSX_EN)
                if (CY_CAPSENSE_CSX_GROUP == ptrWdCfg->senseMethod)
                {
                    Cy_CapSense_DpProcessCsxWidgetStatus(ptrWdCfg);
                }
            #endif /* (CY_CAPSENSE_ENABLE == CY_CAPSENSE_CSX_EN) */

            #if (CY_CAPSENSE_ENABLE == CY_CAPSENSE_CSD_EN)
                if (CY_CAPSENSE_CSD_GROUP == ptrWdCfg->senseMethod)
                {
                    Cy_CapSense_DpProcessCsdWidgetStatus(ptrWdCfg, context);
                }
            #endif /* (CY_CAPSENSE_ENABLE == CY_CAPSENSE_CSD_EN) */

            /* Placeholder for further methods */
        }
    }
    return capStatus;
}


/*******************************************************************************
* Function Name: Cy_CapSense_ProcessSensorExt
****************************************************************************//**
*
* Performs customized data processing on the selected sensor.
*
* This function performs customized data processing specified by the mode
* parameter on a sensor. This function performs the exact same task
* of the Cy_CapSense_ProcessWidgetExt() function but only on the specified
* sensor instead of all sensors in the widget.
*
* The pipeline scan method (i.e. during scanning of a sensor, processing
* of a previously scanned sensor is performed) can be implemented using this
* function and it may reduce the total scan/process time, increase the refresh
* rate, and decrease the power consumption. For more details, refer to
* function usage example below.
*
* \note
* For the the fifth CAPSENSE&trade; HW generation an extra processing should be
* performed prior a call of this function:
* * A raw count pre-processing calling either the Cy_CapSense_PreProcessWidget()
*   or Cy_CapSense_PreProcessSensor() functions.
* * A deconvolution for widgets with multi-phase Tx calling the
*   Cy_CapSense_ProcessWidgetMptxDeconvolution() function.
* In this case a full processing flow consists of the following:
* * Cy_CapSense_PreProcessWidget()
* * Cy_CapSense_ProcessWidgetMptxDeconvolution()
* * Cy_CapSense_ProcessSensorExt() - each sensor
* * Cy_CapSense_ProcessWidgetExt()
*
* \param widgetId
* Specifies the ID number of the widget. A macro for the widget ID can be found
* in the cycfg_capsense.h file defined as CY_CAPSENSE_<WIDGET_NAME>_WDGT_ID.
*
* \param sensorId
* Specifies the ID number of the sensor within the widget. A macro for the
* sensor ID within a specified widget can be found in the cycfg_capsense.h
* file defined as CY_CAPSENSE_<WIDGET_NAME>_SNS<SENSOR_NUMBER>_ID.
*
* \param mode
* Specifies the type of the sensor processing that must be executed for the
* specified sensor:
* 1. Bits [31..5] - Reserved
* 2. Bits [4..0]  - CY_CAPSENSE_PROCESS_ALL - Executes all the tasks
* 3. Bit [4]      - CY_CAPSENSE_PROCESS_THRESHOLDS - Updates the thresholds
*                   (only in auto-tuning mode)
* 4. Bit [3]      - CY_CAPSENSE_PROCESS_CALC_NOISE - Calculates the noise
*                   (only in auto-tuning mode)
* 5. Bit [2]      - CY_CAPSENSE_PROCESS_DIFFCOUNTS - Updates the diff count
* 6. Bit [1]      - CY_CAPSENSE_PROCESS_BASELINE - Updates the baseline
* 7. Bit [0]      - CY_CAPSENSE_PROCESS_FILTER - Runs the firmware filters
*
* \param context
* The pointer to the CAPSENSE&trade; context structure \ref cy_stc_capsense_context_t.
*
* \return
* Returns the status of the sensor process operation:
* - CY_CAPSENSE_STATUS_SUCCESS      - The processing is successfully performed.
* - CY_CAPSENSE_STATUS_BAD_PARAM    - The input parameter is invalid.
* - CY_CAPSENSE_STATUS_BAD_DATA     - The processing failed.
*
* \funcusage
*
* An example demonstrates pipeline implementation of sensor scanning and
* processing:
* \snippet capsense/snippet/main.c snippet_Cy_CapSense_ProcessSensorExt
*
*******************************************************************************/
cy_capsense_status_t Cy_CapSense_ProcessSensorExt(
                uint32_t widgetId,
                uint32_t sensorId,
                uint32_t mode,
                const cy_stc_capsense_context_t * context)
{
    cy_capsense_status_t capStatus = CY_CAPSENSE_STATUS_BAD_PARAM;
    uint32_t freqChIndex;
    uint32_t snsHistorySize;
    uint16_t * ptrSnsBslnInv;
    uint16_t * ptrHistory;
    uint8_t  * ptrHistoryLow = NULL;
    cy_stc_capsense_sensor_context_t * ptrSnsCxt;
    const cy_stc_capsense_widget_config_t * ptrWdCfg;

    if (widgetId < context->ptrCommonConfig->numWd)
    {
        ptrWdCfg = &context->ptrWdConfig[widgetId];
        if (sensorId < ptrWdCfg->numSns)
        {
            snsHistorySize = (uint32_t)ptrWdCfg->rawFilterConfig & CY_CAPSENSE_RC_FILTER_SNS_HISTORY_SIZE_MASK;
            capStatus = CY_CAPSENSE_STATUS_SUCCESS;

            for(freqChIndex = 0u; freqChIndex < CY_CAPSENSE_CONFIGURED_FREQ_NUM; freqChIndex++)
            {
                ptrSnsCxt = &ptrWdCfg->ptrSnsContext[sensorId + (freqChIndex * context->ptrCommonConfig->numSns)];
                ptrSnsBslnInv = &ptrWdCfg->ptrBslnInv[sensorId + (freqChIndex * context->ptrCommonConfig->numSns)];
                ptrHistory = &ptrWdCfg->ptrRawFilterHistory[(freqChIndex * (CY_CAPSENSE_RAW_HISTORY_SIZE / CY_CAPSENSE_CONFIGURED_FREQ_NUM)) +
                                                            (snsHistorySize * sensorId)];
                if(CY_CAPSENSE_IIR_FILTER_PERFORMANCE == (ptrWdCfg->rawFilterConfig & CY_CAPSENSE_RC_FILTER_IIR_MODE_MASK))
                {
                    ptrHistoryLow = &ptrWdCfg->ptrRawFilterHistoryLow[freqChIndex *
                            (CY_CAPSENSE_IIR_HISTORY_LOW_SIZE / CY_CAPSENSE_CONFIGURED_FREQ_NUM)];
                }

                #if (CY_CAPSENSE_ENABLE == CY_CAPSENSE_CSX_EN)
                    if (CY_CAPSENSE_CSX_GROUP == ptrWdCfg->senseMethod)
                    {
                        capStatus = Cy_CapSense_DpProcessCsxSensorRawCountsExt(ptrWdCfg, ptrSnsCxt,
                                ptrHistory, ptrHistoryLow, mode, ptrSnsBslnInv, context);
                    }
                #endif /* (CY_CAPSENSE_ENABLE == CY_CAPSENSE_CSX_EN) */

                #if (CY_CAPSENSE_ENABLE == CY_CAPSENSE_CSD_EN)
                    if (CY_CAPSENSE_CSD_GROUP == ptrWdCfg->senseMethod)
                    {
                        capStatus = Cy_CapSense_DpProcessCsdSensorRawCountsExt(ptrWdCfg, ptrSnsCxt,
                                ptrHistory, ptrHistoryLow, mode, ptrSnsBslnInv, context);
                    }
                #endif /* (CY_CAPSENSE_ENABLE == CY_CAPSENSE_CSD_EN) */

                /* Placeholder for further methods */
            }
            #if (CY_CAPSENSE_DISABLE != CY_CAPSENSE_MULTI_FREQUENCY_SCAN_EN)
                ptrSnsCxt = ptrWdCfg->ptrSnsContext;
                Cy_CapSense_RunMfsFiltering(ptrSnsCxt, context);
            #endif
        }
    }
    return capStatus;
}


/*******************************************************************************
* Function Name: Cy_CapSense_Wakeup
****************************************************************************//**
*
* Resumes the middleware after System Deep Sleep.
*
* This function is used to resume the middleware operation after exiting
* System Deep Sleep. After the CAPSENSE&trade; HW block is powered off,
* an extra delay is required to establish the correct operation of
* the CAPSENSE&trade; HW block.
*
* This function is called by the Cy_CapSense_DeepSleepCallback() function after
* exiting System Deep Sleep if the CAPSENSE&trade; Deep Sleep callback is registered.
*
* \param context
* The pointer to the CAPSENSE&trade; context structure \ref cy_stc_capsense_context_t.
*
*******************************************************************************/
void Cy_CapSense_Wakeup(const cy_stc_capsense_context_t * context)
{
    Cy_SysLib_DelayUs((uint16_t)context->ptrCommonConfig->analogWakeupDelay);
}


/*******************************************************************************
* Function Name: Cy_CapSense_DeepSleepCallback
****************************************************************************//**
*
* Handles CPU active to System Deep Sleep power mode transition for the CAPSENSE&trade;
* middleware.
*
* Calling this function directly from the application program is not recommended.
* Instead, Cy_SysPm_CpuEnterDeepSleep() should be used for the CPU active to System Deep Sleep
* power mode transition of the device.
* \note
* After the CPU Deep Sleep transition, the device automatically goes
* to System Deep Sleep if all conditions are fulfilled: another core is
* in CPU Deep Sleep, all the peripherals are ready to System Deep Sleep, etc.
* (see details in the device TRM).
*
* For proper operation of the CAPSENSE&trade; middleware during the CPU active to
* System Deep Sleep mode transition, a callback to this function should be registered
* using the Cy_SysPm_RegisterCallback() function with CY_SYSPM_DEEPSLEEP
* type. After the callback is registered, this function is called by the
* Cy_SysPm_CpuEnterDeepSleep() function to prepare the middleware to the device
* power mode transition.
*
* When this function is called with CY_SYSPM_CHECK_READY as an input, this
* function returns CY_SYSPM_SUCCESS if no scanning is in progress or not
* a single HW block is captured by the CAPSENSE&trade; middleware. Otherwise
* CY_SYSPM_FAIL is returned. If CY_SYSPM_FAIL status is returned, a device
* cannot change the power mode without completing the current scan as
* a transition to System Deep Sleep during the scan can disrupt the middleware
* operation.
*
* When this function is called with CY_SYSPM_AFTER_TRANSITION as an input, then
* the Cy_CapSense_Wakeup() function is called to resume the middleware
* operation after exiting System Deep Sleep. If there are no CAPSENSE&trade; captured
* HW blocks the Cy_CapSense_Wakeup() function calling is omitted and restoring
* CAPSENSE&trade; immediately after Deep Sleep without the wake-up delay can lead to
* unpredictable behavior.
*
* For details of SysPm types and macros refer to the SysPm section of the
* PDL documentation.
*
* \param callbackParams
* Refer to the description of the cy_stc_syspm_callback_params_t type in the
* Peripheral Driver Library documentation.
*
* \param mode
* Specifies mode cy_en_syspm_callback_mode_t.
*
* \return
* Returns the status cy_en_syspm_status_t of the operation requested
* by the mode parameter:
* - CY_SYSPM_SUCCESS  - System Deep Sleep power mode can be entered.
* - CY_SYSPM_FAIL     - System Deep Sleep power mode cannot be entered.
*
*******************************************************************************/
cy_en_syspm_status_t Cy_CapSense_DeepSleepCallback(
                cy_stc_syspm_callback_params_t * callbackParams,
                cy_en_syspm_callback_mode_t mode)
{
    cy_en_syspm_status_t retVal = CY_SYSPM_SUCCESS;
    const cy_stc_capsense_context_t * capsenseCxt = (cy_stc_capsense_context_t *)callbackParams->context;

    #if (CY_CAPSENSE_PLATFORM_BLOCK_FOURTH_GEN)
        cy_en_csd_key_t mwKey;

        switch(mode)
        {
            case CY_SYSPM_CHECK_READY:
                mwKey = Cy_CSD_GetLockStatus(capsenseCxt->ptrCommonConfig->ptrCsdBase, capsenseCxt->ptrCommonConfig->ptrCsdContext);

                if (CY_CSD_CAPSENSE_KEY == mwKey)
                {
                    if (CY_CAPSENSE_NOT_BUSY != Cy_CapSense_IsBusy(capsenseCxt))
                    {
                        retVal = CY_SYSPM_FAIL;
                    }
                }
                break;

            case CY_SYSPM_AFTER_TRANSITION:
                mwKey = Cy_CSD_GetLockStatus(capsenseCxt->ptrCommonConfig->ptrCsdBase, capsenseCxt->ptrCommonConfig->ptrCsdContext);

                if (CY_CSD_CAPSENSE_KEY == mwKey)
                {
                    Cy_CapSense_Wakeup(capsenseCxt);
                }
                break;

            default:
                /* No action for other modes */
                break;
        }
    #else /* (CY_CAPSENSE_PLATFORM_BLOCK_FIFTH_GEN) */
        uint32_t curChIndex;
        const cy_stc_msc_channel_config_t * ptrMscChCfg = &capsenseCxt->ptrCommonConfig->ptrMscChConfig[0u];

        switch(mode)
        {
            case CY_SYSPM_CHECK_READY:
                if (CY_CAPSENSE_NOT_BUSY != Cy_CapSense_IsBusy(capsenseCxt))
                {
                    retVal = CY_SYSPM_FAIL;
                }
                break;

            case CY_SYSPM_AFTER_TRANSITION:
                for (curChIndex = 0u; curChIndex < CY_CAPSENSE_TOTAL_CH_NUMBER; curChIndex++)
                {
                    if (CY_MSC_CAPSENSE_KEY == Cy_MSC_GetLockStatus(ptrMscChCfg->ptrMscBase,
                                                                    ptrMscChCfg->ptrMscContext))
                    {
                        Cy_CapSense_Wakeup(capsenseCxt);
                        break;
                    }
                    ptrMscChCfg++;
                }
                break;

            default:
                /* No action for other modes */
                break;
        }
    #endif

    return(retVal);
}

#if ((CY_CAPSENSE_DISABLE != CY_CAPSENSE_GESTURE_EN) || \
     (CY_CAPSENSE_DISABLE != CY_CAPSENSE_BALLISTIC_MULTIPLIER_EN))
/*******************************************************************************
* Function Name: Cy_CapSense_IncrementGestureTimestamp
****************************************************************************//**
*
* Increments the timestamp register for the predefined timestamp interval.
*
* A timestamp is required for operation of the Gesture and Ballistic multiplier
* feature. Hence this function and timestamp is required only if the Gesture
* detection or Ballistic multiplier feature is enabled.
*
* This function increments the timestamp by the interval specified
* in the context->ptrCommonContext->timestampInterval register. The unit for
* the timestamp and timestamp interval is milliseconds and the default value of the
* interval is 1.
*
* The application program must periodically call this
* function or register a periodic callback to this function to keep the
* timestamp updated and operational for the operation of the Gesture and
* Ballistic multiplier feature.
*
* The timestamp can be updated in one of the three methods:
* 1. Register a periodic callback for the
*    Cy_CapSense_IncrementGestureTimestamp() function.
* 2. Periodically call the Cy_CapSense_IncrementGestureTimestamp() function
*    from the application program.
* 3. Directly modify the timestamp using the
*    Cy_CapSense_SetGestureTimestamp() function.
*
* See the function usage example below for more details.
*
* The interval at which this function is called should match with interval
* defined in context->ptrCommonContext->timestampInterval register. Either the
* register value can be updated to match the callback interval or the callback
* can be made at interval set in the register.
*
* If a timestamp is available from another source, the application program
* may choose to periodically update the timestamp by using the
* Cy_CapSense_SetGestureTimestamp() function instead of
* registering a callback.
*
* \param context
* The pointer to the CAPSENSE&trade; context structure \ref cy_stc_capsense_context_t.
*
* \funcusage
*
* An example of timestamp updating:
* \snippet capsense/snippet/main.c snippet_Cy_CapSense_Timestamp
*
*******************************************************************************/
void Cy_CapSense_IncrementGestureTimestamp(cy_stc_capsense_context_t * context)
{
    context->ptrCommonContext->timestamp +=
                context->ptrCommonContext->timestampInterval;
}


/*******************************************************************************
* Function Name: Cy_CapSense_SetGestureTimestamp
****************************************************************************//**
*
* Rewrites the timestamp register by the specified value.
*
* This function writes the specified value into the middleware timestamp
* context->ptrCommonContext->timestamp register.
*
* If a timestamp is available from another source, the application program
* may choose to periodically update the timestamp by using this function
* instead of registering a callback.
*
* Do not modify the timestamp arbitrarily or simultaneously use with
* the Cy_CapSense_IncrementGestureTimestamp() function, which may result in
* unexpected result.
*
* \param value
* Specifies the timestamp value (in ms).
*
* \param context
* The pointer to the CAPSENSE&trade; context structure \ref cy_stc_capsense_context_t.
*
*******************************************************************************/
void Cy_CapSense_SetGestureTimestamp(
                uint32_t value,
                cy_stc_capsense_context_t * context)
{
    context->ptrCommonContext->timestamp = value;
}
#endif /* ((CY_CAPSENSE_DISABLE != CY_CAPSENSE_GESTURE_EN) || \
           (CY_CAPSENSE_DISABLE != CY_CAPSENSE_BALLISTIC_MULTIPLIER_EN)) */

/*******************************************************************************
* Function Name: Cy_CapSense_Restore
****************************************************************************//**
*
* Resumes the middleware operation if the Cy_CapSense_Save() function was
* called previously.
*
* This function, along with the Cy_CapSense_Save() function is specifically
* designed for ease of use and supports time multiplexing of the CAPSENSE&trade; HW
* block among multiple middleware. When the CAPSENSE&trade; HW blocks are shared by
* multiple middleware, this function can be used to restore the previous state of
* the CAPSENSE&trade; HW block(s) and CAPSENSE&trade; Middleware is saved using the
* Cy_CapSense_Save() function. See the function usage example below for
* details on usage.
*
* This function performs the same tasks as Cy_CapSense_Init() function and is
* kept for API consistency among middlewares. It is recommended to use
* Cy_CapSense_Save() and Cy_CapSense_Restore() functions to implement
* time-multiplexed mode instead of Cy_CapSense_DeInit() and Cy_CapSense_Init()
* functions for further compatibility.
*
* \param context
* The pointer to the CAPSENSE&trade; context structure \ref cy_stc_capsense_context_t.
*
* \return
* Returns the status of the resume process. If CY_CAPSENSE_STATUS_SUCCESS is not
* received, the resume process fails and retries may be required.
*
* \funcusage
*
* An example of sharing the CAPSENSE&trade; HW block by CAPSENSE&trade; and CSDADC middleware:
* \snippet capsense/snippet/main.c snippet_Cy_CapSense_TimeMultiplex
*
*******************************************************************************/
cy_capsense_status_t Cy_CapSense_Restore(cy_stc_capsense_context_t * context)
{
    #if (CY_CAPSENSE_PLATFORM_BLOCK_FOURTH_GEN)

        cy_capsense_status_t capStatus = CY_CAPSENSE_STATUS_INVALID_STATE;
        cy_en_csd_key_t mvKey;
        cy_en_csd_status_t csdHwStatus;
        cy_stc_csd_context_t * ptrCsdCxt = context->ptrCommonConfig->ptrCsdContext;
        CSD_Type * ptrCsdBaseAdd = context->ptrCommonConfig->ptrCsdBase;
        uint32_t watchdogCounter;

        /* Number of cycle of one for() loop */
        const uint32_t cyclesPerLoop = 5u;
        /* Timeout in microseconds */
        const uint32_t watchdogTimeoutUs = 10000u;

        /* Get the CSD HW block status */
        mvKey = Cy_CSD_GetLockStatus(ptrCsdBaseAdd, ptrCsdCxt);
        if(CY_CSD_NONE_KEY == mvKey)
        {
            /* Reset CSD HW block sequencer state always to handle a corner case when the sequencer is not in the idle state */
            context->ptrCommonConfig->ptrCsdBase->INTR_MASK = CY_CAPSENSE_CSD_INTR_MASK_CLEAR_MSK;
            context->ptrCommonConfig->ptrCsdBase->SEQ_START = CY_CAPSENSE_CSD_SEQ_START_ABORT_MSK;
            watchdogCounter = Cy_CapSense_WatchdogCyclesNum(watchdogTimeoutUs,
                context->ptrCommonConfig->cpuClkHz / CY_CAPSENSE_CONVERSION_MEGA, cyclesPerLoop);
            do
            {
                csdHwStatus = Cy_CSD_GetConversionStatus(ptrCsdBaseAdd, ptrCsdCxt);
                watchdogCounter--;
            }
            while((CY_CSD_BUSY == csdHwStatus) && (0u != watchdogCounter));

            if(CY_CSD_SUCCESS == csdHwStatus)
            {
                #if (CY_CAPSENSE_DISABLE != CY_CAPSENSE_USE_CAPTURE)
                    csdHwStatus = Cy_CSD_Capture(ptrCsdBaseAdd, CY_CSD_CAPSENSE_KEY, ptrCsdCxt);
                #else
                    csdHwStatus = Cy_CSD_Init(ptrCsdBaseAdd, &cy_capsense_csdCfg, CY_CSD_CAPSENSE_KEY, ptrCsdCxt);
                #endif

                if(CY_CSD_SUCCESS == csdHwStatus)
                {
                    capStatus = CY_CAPSENSE_STATUS_SUCCESS;
                }
            }
        }
        return (capStatus);
    #else /* (CY_CAPSENSE_PLATFORM_BLOCK_FIFTH_GEN) */
        uint32_t curChIndex;
        cy_en_msc_status_t mscHwStatus;
        cy_capsense_status_t capStatus = CY_CAPSENSE_STATUS_SUCCESS;
        const cy_stc_msc_channel_config_t * ptrMscChCfg = &context->ptrCommonConfig->ptrMscChConfig[0u];

        for (curChIndex = 0u; curChIndex < CY_CAPSENSE_TOTAL_CH_NUMBER; curChIndex++)
        {
            /* Get MSC HW blocks statuses */
            if(CY_MSC_NONE_KEY != Cy_MSC_GetLockStatus(ptrMscChCfg->ptrMscBase, ptrMscChCfg->ptrMscContext))
            {
                capStatus = CY_CAPSENSE_STATUS_HW_LOCKED;
                break;
            }
            ptrMscChCfg++;
        }

        if (capStatus == CY_CAPSENSE_STATUS_SUCCESS)
        {
            capStatus = Cy_CapSense_SwitchHwConfiguration(CY_CAPSENSE_HW_CONFIG_CAPTURED_DEFAULT, context);
            if (capStatus == CY_CAPSENSE_STATUS_SUCCESS)
            {
                ptrMscChCfg = &context->ptrCommonConfig->ptrMscChConfig[0u];
                /* Capture MSC HW blocks */
                for (curChIndex = 0u; curChIndex < CY_CAPSENSE_TOTAL_CH_NUMBER; curChIndex++)
                {
                    #if (CY_CAPSENSE_DISABLE != CY_CAPSENSE_USE_CAPTURE)
                        mscHwStatus = Cy_MSC_Capture(ptrMscChCfg->ptrMscBase,
                                                CY_MSC_CAPSENSE_KEY, ptrMscChCfg->ptrMscContext);
                    #else
                        mscHwStatus = Cy_MSC_Init(ptrMscChCfg->ptrMscBase, &cy_capsense_mscCfg,
                                                  CY_MSC_CAPSENSE_KEY, ptrMscChCfg->ptrMscContext);
                    #endif

                    if(CY_MSC_SUCCESS != mscHwStatus)
                    {
                        capStatus = CY_CAPSENSE_STATUS_INVALID_STATE;
                        break;
                    }
                    ptrMscChCfg++;
                }
            }
        }

        return (capStatus);
    #endif
}


/*******************************************************************************
* Function Name: Cy_CapSense_Save
****************************************************************************//**
*
* Saves the state of CAPSENSE&trade; so the functionality can be restored
* using the Cy_CapSense_Restore() function.
*
* This function, along with the Cy_CapSense_Restore() function, is specifically
* designed for ease of use and supports time multiplexing of the CAPSENSE&trade; HW
* block among multiple middleware. When the CAPSENSE&trade; HW block is shared by
* multiple middleware, this function can be used to save the current state of
* the CAPSENSE&trade; HW block and CAPSENSE&trade; Middleware prior to releasing the
* CAPSENSE&trade; HW block for use by other middleware. See the function usage example
* below for details on usage.
*
* This function performs the same tasks as the Cy_CapSense_DeInit() function and is
* kept for API consistency among middlewares. It is recommended to use
* Cy_CapSense_Save() and Cy_CapSense_Restore() functions to implement
* Time-multiplexed mode instead of Cy_CapSense_DeInit() and Cy_CapSense_Init()
* functions for further compatibility.
*
* This function performs the following operations:
* * Releases the CAPSENSE&trade; HW block.
* * Configures sensor pins to the default state and disconnects them from
*   analog buses.
* * Disconnects external capacitors from analog buses.
* * Sets the middleware state to default.
*
* \param context
* The pointer to the CAPSENSE&trade; context structure \ref cy_stc_capsense_context_t.
*
* \return
* Returns the status of the process. If CY_CAPSENSE_STATUS_SUCCESS is not received,
* the save process fails and retries may be required.
*
* \funcusage
*
* An example of sharing the CAPSENSE&trade; HW block by the CapSense and CSDADC middleware.<br>
* Declares the CapSense_ISR_cfg variable:
* \snippet capsense/snippet/main.c snippet_m4_capsense_interrupt_source_declaration
*
* Declares the CSDADC_ISR_cfg variable:
* \snippet capsense/snippet/main.c snippet_m4_adc_interrupt_source_declaration
*
* Defines the CapSense interrupt handler:
* \snippet capsense/snippet/main.c snippet_CapSense_Interrupt
*
* Defines the CSDADC interrupt handler:
* \snippet capsense/snippet/main.c snippet_CSDADC_Interrupt
*
* The part of the main.c FW flow:
* \snippet capsense/snippet/main.c snippet_Cy_CapSense_TimeMultiplex
*
*******************************************************************************/
cy_capsense_status_t Cy_CapSense_Save(cy_stc_capsense_context_t * context)
{
    #if (CY_CAPSENSE_PLATFORM_BLOCK_FOURTH_GEN)

        cy_capsense_status_t capStatus = CY_CAPSENSE_STATUS_INVALID_STATE;
        cy_en_csd_status_t initStatus;

        if (CY_CAPSENSE_NOT_BUSY == Cy_CapSense_IsBusy(context))
        {
            /* Disconnect external capacitors and sensor pins from analog bus */
            (void)Cy_CapSense_SwitchSensingMode(CY_CAPSENSE_UNDEFINED_GROUP, context);

            /* Release the CSD HW block */
            initStatus = Cy_CSD_DeInit(
                            context->ptrCommonConfig->ptrCsdBase,
                            CY_CSD_CAPSENSE_KEY,
                            context->ptrCommonConfig->ptrCsdContext);

            if (CY_CSD_SUCCESS == initStatus)
            {
                capStatus = CY_CAPSENSE_STATUS_SUCCESS;
            }
        }

        return capStatus;

    #else /* (CY_CAPSENSE_PLATFORM_BLOCK_FIFTH_GEN) */

        uint32_t curChIndex;
        cy_en_msc_status_t initStatus;
        cy_capsense_status_t capStatus = CY_CAPSENSE_STATUS_SUCCESS;
        const cy_stc_msc_channel_config_t * ptrMscChannel = context->ptrCommonConfig->ptrMscChConfig;

        if (CY_CAPSENSE_NOT_BUSY == Cy_CapSense_IsBusy(context))
        {
            for (curChIndex = 0u; curChIndex < CY_CAPSENSE_TOTAL_CH_NUMBER; curChIndex++)
            {
                /* Get MSC HW blocks statuses */
                if(CY_MSC_CAPSENSE_KEY != Cy_MSC_GetLockStatus(ptrMscChannel[curChIndex].ptrMscBase, ptrMscChannel[curChIndex].ptrMscContext))
                {
                    capStatus = CY_CAPSENSE_STATUS_HW_LOCKED;
                    break;
                }
            }

            if (CY_CAPSENSE_STATUS_SUCCESS == capStatus)
            {
                capStatus = Cy_CapSense_SwitchHwConfiguration(CY_CAPSENSE_HW_CONFIG_UNDEFINED, context);
                if (capStatus == CY_CAPSENSE_STATUS_SUCCESS)
                {
                    for (curChIndex = 0u; curChIndex < CY_CAPSENSE_TOTAL_CH_NUMBER; curChIndex++)
                    {
                        initStatus = Cy_MSC_DeInit(ptrMscChannel[curChIndex].ptrMscBase, CY_MSC_CAPSENSE_KEY, ptrMscChannel[curChIndex].ptrMscContext);
                        if (CY_MSC_SUCCESS != initStatus)
                        {
                            capStatus = CY_CAPSENSE_STATUS_HW_LOCKED;
                            break;
                        }
                    }
                }
            }
        }
        else
        {
            capStatus = CY_CAPSENSE_STATUS_HW_BUSY;
        }

        return capStatus;

    #endif
}


/*******************************************************************************
* Function Name: Cy_CapSense_RegisterCallback
****************************************************************************//**
*
* Registers a ures's callback function.
*
* The registered function will be called by the CAPSENSE&trade; middleware when
* the specified event \ref cy_en_capsense_callback_event_t has occurred in
* the CAPSENSE&trade; middleware.
*
* \param callbackType
* The event on which the registered user's function is called by the CAPSENSE&trade;
* middleware. Refer to \ref cy_en_capsense_callback_event_t for the list of
* supported events.
*
* \param callbackFunction
* The pointer to the user's callback function to be called by the middleware.
*
* \param context
* The pointer to the CAPSENSE&trade; context structure \ref cy_stc_capsense_context_t.
*
* \return
* Returns the status of the callback registration:
* - CY_CAPSENSE_STATUS_SUCCESS      - The action performed successfully.
* - CY_CAPSENSE_STATUS_BAD_PARAM    - The input parameter is invalid.
*
*******************************************************************************/
cy_capsense_status_t Cy_CapSense_RegisterCallback(
                cy_en_capsense_callback_event_t callbackType,
                cy_capsense_callback_t callbackFunction,
                cy_stc_capsense_context_t * context)
{
    cy_capsense_status_t retVal = CY_CAPSENSE_STATUS_SUCCESS;

    if((NULL != callbackFunction) && (NULL != context))
    {

        switch(callbackType)
        {
            case CY_CAPSENSE_START_SAMPLE_E:
                context->ptrInternalContext->ptrSSCallback = callbackFunction;
                break;
            case CY_CAPSENSE_END_OF_SCAN_E:
                context->ptrInternalContext->ptrEOSCallback = callbackFunction;
                break;
            default:
                retVal = CY_CAPSENSE_STATUS_BAD_PARAM;
                break;
        }
    }
    else
    {
        retVal = CY_CAPSENSE_STATUS_BAD_PARAM;
    }

    return(retVal);
}


/*******************************************************************************
* Function Name: Cy_CapSense_UnRegisterCallback
****************************************************************************//**
*
* This function unregisters a previously registered user's callback function
* in the CAPSENSE&trade; middleware.
*
* \param callbackType
* The event on which the callback function should be unregistered.
* Refer to \ref cy_en_capsense_callback_event_t for the list of
* supported events.
*
* \param context
* The pointer to the CAPSENSE&trade; context structure \ref cy_stc_capsense_context_t.
*
* \return
* Returns the status of the callback deregistration:
* - CY_CAPSENSE_STATUS_SUCCESS      - The action performed successfully.
* - CY_CAPSENSE_STATUS_BAD_PARAM    - The input parameter is invalid.
*
*******************************************************************************/
cy_capsense_status_t Cy_CapSense_UnRegisterCallback(
                cy_en_capsense_callback_event_t callbackType,
                cy_stc_capsense_context_t * context)
{
    cy_capsense_status_t retVal = CY_CAPSENSE_STATUS_SUCCESS;

    if(NULL != context)
    {
        switch(callbackType)
        {
            case CY_CAPSENSE_START_SAMPLE_E:
                context->ptrInternalContext->ptrSSCallback = NULL;
                break;
            case CY_CAPSENSE_END_OF_SCAN_E:
                context->ptrInternalContext->ptrEOSCallback = NULL;
                break;
            default:
                retVal = CY_CAPSENSE_STATUS_BAD_PARAM;
                break;
        }
    }
    else
    {
        retVal = CY_CAPSENSE_STATUS_BAD_PARAM;
    }

    return(retVal);

}

#endif /* (defined(CY_IP_MXCSDV2) || defined(CY_IP_M0S8CSDV2) || defined(CY_IP_M0S8MSCV3)) */


/* [] END OF FILE */
